
#include "member_BCapsule.h"

using namespace BWE;

member_BCapsule::member_BCapsule(BCapsule* capsule)
{
	boss = capsule;
	radius = 1.0f;
	height = 1.0f;
	sides = 12;
	heightSegments = 5;
	radiusSegments = 4;
	prepare();
}
member_BCapsule::~member_BCapsule()
{

}

void member_BCapsule::prepare()
{
	if (sines.size() != sides)
	{
		sines.resize(sides);
		coses.resize(sides);
		BReal sr = PI2 / sides;
		for (int i = 0; i < sides; i++)
		{
			BReal angle = i * sr;
			coses[i] = cos(angle);
			sines[i] = sin(angle);
		}
	}
}

void member_BCapsule::rebuild()
{
	flankSize = (sides + 1) * (heightSegments + 1);

	BVectorArray* vertices = boss->vertices();
	BVectorArray* normals = boss->normals();
	BCoordArray* texCoords = boss->texCoords();
	if (!vertices || vertices->size() != flankSize)
	{
		vertices = new BVectorArray(flankSize);
		normals = new BVectorArray(flankSize);
		texCoords = new BCoordArray(flankSize);
		boss->setVertices(vertices);
		boss->setNormals(normals);
		boss->setTexCoords(texCoords);
	}
	boss->clearElements();

	BReal hh = height / 2;
	if (heightSegments > 0)//make flank
	{
		BReal sz = height / heightSegments;
		BReal sr = PI2 / sides;
		float stx = 1.0f / sides;
		float sty = 1.0f / heightSegments;
		for (int r = 0; r < heightSegments + 1; r++)
		{
			BReal z = sz * r - hh;
			float ty = sty * r;
			int head = r * (sides + 1);
			for (int c = 0; c < sides; c++)
			{
				float tx = stx * c;
				BReal nx = coses[c];
				BReal ny = sines[c];
				(*vertices)[head + c].set(nx * radius, ny * radius, z);
				(*normals)[head + c].set(nx, ny, 0);
				(*texCoords)[head + c].set(tx, 1 - ty);
			}
			(*vertices)[head + sides] = vertices->at(head);
			(*normals)[head + sides] = normals->at(head);
			(*texCoords)[head + sides].set(1.0f, 1 - ty);
		}
		BIntArray* indices = new BIntArray(heightSegments * sides * 4);
		for (int r = 0; r < heightSegments; r++)
		{
			int head = r * (sides + 1);
			int pos = r * sides * 4;
			for (int c = 0; c < sides; c++)
			{
				int i0 = head + c;
				int i1 = head + c + 1;
				int i2 = i0 + sides + 1;
				int i3 = i1 + sides + 1;
				(*indices)[pos + c * 4 + 0] = i0;
				(*indices)[pos + c * 4 + 1] = i1;
				(*indices)[pos + c * 4 + 2] = i3;
				(*indices)[pos + c * 4 + 3] = i2;
			}
		}
		boss->addElement(Primitive_Quads, indices)->setName("flank");
	}

	bottomBegin = vertices->size();
	bottomSize = 0;
	if (radiusSegments > 0)
	{
		BReal tcmult = 0.5f / radius;
		if (radiusSegments == 1)
		{
			bottomSize = sides + 1;
			for (int i = 0; i < sides; i++)
			{
				BReal x = coses[i] * radius;
				BReal y = sines[i] * radius;
				vertices->append(BVector(x, y, -hh));
				normals->append(BVector(0, 0, 0));
				texCoords->append(BCoord((x + radius) * tcmult, (y + radius) * tcmult));
			}
			vertices->append(BVector(0, 0, -hh - radius));
			normals->append(BVector(0, 0, -1));
			texCoords->append(BCoord(0.5f, 0.5f));

			BIntArray* indices = new BIntArray(sides * 3);
			int ic = bottomBegin + sides;
			for (int i = 0; i < sides; i++)
			{
				int i0 = bottomBegin + i;
				int i1 = bottomBegin + (i + 1) % sides;
				(*indices)[i * 3] = i1;
				(*indices)[i * 3 + 1] = i0;
				(*indices)[i * 3 + 2] = ic;
			}
			boss->addElement(Primitive_Triangles, indices)->setName("bottom");
		}
		else
		{
			bottomSize = sides * radiusSegments + 1;
			BReal rstep = PI / radiusSegments / 2;
			for (int r = 0; r < radiusSegments; r++)
			{
				BReal z = -sin(r * rstep) * radius;
				BReal len = cos(r * rstep) * radius;
				for (int c = 0; c < sides; c++)
				{
					BReal x = coses[c] * len;
					BReal y = sines[c] * len;
					vertices->append(BVector(x, y, z - hh));
					normals->append(BVector(x, y, z).normal());
					texCoords->append(BCoord((x + radius) * tcmult, (y + radius) * tcmult));
				}
			}
			vertices->append(BVector(0, 0, -hh - radius));
			normals->append(BVector(0, 0, -1));
			texCoords->append(BCoord(0.5f, 0.5f));

			BIntArray* indices = new BIntArray((radiusSegments - 1) * sides * 4);
			for (int r = 0; r < radiusSegments - 1; r++)
			{
				int head = bottomBegin + r * sides;
				int pos = r * sides * 4;
				for (int c = 0; c < sides; c++)
				{
					int i0 = head + c;
					int i1 = head + (c + 1) % sides;
					int i2 = i0 + sides;
					int i3 = i1 + sides;
					(*indices)[pos + c * 4 + 0] = i0;
					(*indices)[pos + c * 4 + 1] = i2;
					(*indices)[pos + c * 4 + 2] = i3;
					(*indices)[pos + c * 4 + 3] = i1;
				}
			}
			boss->addElement(Primitive_Quads, indices)->setName("bottom");

			BIntArray* centralIndices = new BIntArray(sides * 3);
			int head = vertices->size() - sides - 1;
			int ic = vertices->size() - 1;
			for (int i = 0; i < sides; i++)
			{
				int i0 = head + i;
				int i1 = head + (i + 1) % sides;
				(*centralIndices)[i * 3] = i0;
				(*centralIndices)[i * 3 + 1] = ic;
				(*centralIndices)[i * 3 + 2] = i1;
			}
			boss->addElement(Primitive_Triangles, centralIndices)->setName("bottom-center");
		}
	}

	topBegin = vertices->size();
	topSize = 0;
	if (radiusSegments > 0)
	{
		BReal tcmult = 0.5f / radius;
		if (radiusSegments == 1)
		{
			topSize = sides + 1;
			for (int i = 0; i < sides; i++)
			{
				BReal x = coses[i] * radius;
				BReal y = sines[i] * radius;
				vertices->append(BVector(x, y, hh));
				normals->append(BVector(0, 0, 0));
				texCoords->append(BCoord((x + radius) * tcmult, 1 - (y + radius) * tcmult));
			}
			vertices->append(BVector(0, 0, hh + radius));
			normals->append(BVector(0, 0, 1));
			texCoords->append(BCoord(0.5f, 0.5f));

			BIntArray* indices = new BIntArray(sides * 3);
			int ic = vertices->size() - 1;
			for (int i = 0; i < sides; i++)
			{
				int i0 = topBegin + i;
				int i1 = topBegin + (i + 1) % sides;
				(*indices)[i * 3] = i0;
				(*indices)[i * 3 + 1] = i1;
				(*indices)[i * 3 + 2] = ic;
			}
			boss->addElement(Primitive_Triangles, indices)->setName("top");
		}
		else
		{
			topSize = sides * radiusSegments + 1;
			BReal angleStep = PI / radiusSegments / 2;
			for (int r = 0; r < radiusSegments; r++)
			{
				int head = r * (sides + 1);
				BReal z = sin(r * angleStep) * radius;
				BReal len = cos(r * angleStep) * radius;
				for (int c = 0; c < sides; c++)
				{
					BReal x = coses[c] * len;
					BReal y = sines[c] * len;
					vertices->append(BVector(x, y, z + hh));
					normals->append(BVector(x, y, z).normal());
					texCoords->append(BCoord((x + radius) * tcmult, 1 - (y + radius) * tcmult));
				}
			}
			vertices->append(BVector(0, 0, hh + radius));
			normals->append(BVector(0, 0, 1));
			texCoords->append(BCoord(0.5f, 0.5f));

			BIntArray* indices = new BIntArray((radiusSegments - 1) * sides * 4);
			for (int r = 0; r < radiusSegments - 1; r++)
			{
				int head = topBegin + r * sides;
				int pos = r * sides * 4;
				for (int c = 0; c < sides; c++)
				{
					int i0 = head + c;
					int i1 = head + (c + 1) % sides;
					int i2 = i0 + sides;
					int i3 = i1 + sides;
					(*indices)[pos + c * 4 + 0] = i0;
					(*indices)[pos + c * 4 + 1] = i1;
					(*indices)[pos + c * 4 + 2] = i3;
					(*indices)[pos + c * 4 + 3] = i2;
				}
			}
			boss->addElement(Primitive_Quads, indices)->setName("top");

			BIntArray* centralIndices = new BIntArray(sides * 3);
			int head = vertices->size() - sides - 1;
			int ic = vertices->size() - 1;
			for (int i = 0; i < sides; i++)
			{
				int i0 = head + i;
				int i1 = head + (i + 1) % sides;
				(*centralIndices)[i * 3] = i0;
				(*centralIndices)[i * 3 + 1] = i1;
				(*centralIndices)[i * 3 + 2] = ic;
			}
			boss->addElement(Primitive_Triangles, centralIndices)->setName("top-center");
		}
	}

	for (int i = 0; i < sides; i++)
	{
		BVector n = ((*normals)[i] + (*normals)[bottomBegin + i]);
		n.normalize();
		(*normals)[i] = n;
		(*normals)[bottomBegin + i] = n;
	}

	int flankTailBegin = flankSize - sides - 1;
	for (int i = 0; i < sides; i++)
	{
		BVector n = ((*normals)[flankTailBegin + i] + (*normals)[topBegin + i]);
		n.normalize();
		(*normals)[flankTailBegin + i] = n;
		(*normals)[topBegin + i] = n;
	}

}
